package com.dtb.trade.comment;

import com.dtb.trade.entity.Block;
import com.dtb.trade.entity.PointDeal;
import com.dtb.trade.entity.mongodb.first.FirstBlock;
import com.dtb.trade.entity.mongodb.fourth.FourthBlock;
import com.dtb.trade.entity.mongodb.second.SecondBlock;
import com.dtb.trade.entity.mongodb.third.ThirdBlock;
import com.dtb.trade.service.*;
import com.dtb.trade.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author:ChengJian
 * @Description:
 * @Date: Created in 上午9:40 2018/8/10
 */
@Component
public class TradeTask {


    @Autowired
    RedisService redisService;

    @Autowired
    TradeService tradeService;

    @Autowired
    MongoTradeService mongoTradeService;

    @Autowired
    SecondBlockService secondService;

    @Autowired
    ThirdBlockService thirdService;

    @Autowired
    FourthBlockService fourthService;


    //单节点mysql 区块记账
    @Scheduled(cron = "0 0 16 * * ?")
    private void task(){
        List<PointDeal> list = tradeService.gainAllTrade();

        if (list.size()>0){
            //获取交易块
            Block block = null;
            String index = redisService.get("blockIndex");
            if (StringUtils.isEmpty(index)){
                //直接从数据库查询
                boolean isHave = tradeService.isBlock();
                if (!isHave){
                    //生成创世区块
                    tradeService.hyperledgerTwo(firstBlockforMysql(),list);
                }else {
                    block = tradeService.getNewBlock();
                    tradeService.hyperledger(block,list);
                }

            }else {
                //查询区块信息
                block = tradeService.selectBlock(Integer.valueOf(index));
                if (block != null){
                    tradeService.hyperledger(block,list);
                }else {
                    System.out.println("区块出现异常");
                }
            }
        }
    }

    //单节点mongodb区块记账
    @Scheduled(cron = "0 0 18 * * ?")
    public void singleTask(){
        List<PointDeal> list = tradeService.gainAllTrade();

        if (list.size()>0){
            //获取交易块
            FirstBlock block = new FirstBlock();
            String index = redisService.get("blockIndex");
            if (StringUtils.isEmpty(index) && index == null){
                //直接从数据库查询
                boolean isHave = mongoTradeService.isHaveBlock();
                if (!isHave){
                    //生成创世区块
                    mongoTradeService.tally(firstBlockforMongodb(),list);
                }else{
                    block = mongoTradeService.getNewest();
                    mongoTradeService.hyperledger(block,list);
                }

            }else {
                //查询区块信息
                block = mongoTradeService.getBlockByIndex(Integer.valueOf(index));
                if (block != null){
                    mongoTradeService.hyperledger(block,list);
                }else {
                    System.out.println("区块出现异常");
                }
            }
        }
    }

    //多节点mongodb区块记账
    @Scheduled(cron = "0 0 17 * * ?")
    public void mostTask(){
        boolean isHave = mongoTradeService.isHaveBlock();

        if (isHave){

            boolean first  = prove(1);
            boolean second = prove(2);
            boolean third  = prove(3);
            boolean fourth = prove(4);

            int sumtrue = 0;


            if (first){
                sumtrue += 1;
            }

            if (second){
                sumtrue += 1;
            }

            if (third){
                sumtrue += 1;
            }

            if (fourth){
                sumtrue += 1;
            }

            if (sumtrue <3 ){
                try {
                    throw new BlockException("msg","节点故障太多");
                } catch (BlockException e) {
                    e.printStackTrace();
                }
            }
            //查询N节点最新区块
            FirstBlock firstBlock   = mongoTradeService.getNewest();
            SecondBlock secondBlock = secondService.getNewest();
            ThirdBlock thirdBlock   = thirdService.getNewest();
            FourthBlock fourthBlock = fourthService.getNewest();

            String firstHash        = firstBlock.getHash();
            String secondHash       = secondBlock.getHash();
            String thirdHash        = thirdBlock.getHash();
            String fourthHash       = fourthBlock.getHash();

            if (!((firstHash.equals(secondHash))|(secondHash.equals(thirdHash))|(thirdHash.equals(fourthHash)))){
                try {
                    throw new BlockException("msg","多节点最新区块信息不同，有人篡改信息或者程序出现问题");
                } catch (BlockException e) {
                    e.printStackTrace();
                }
            }
        }


        List<PointDeal> list = tradeService.gainAllTrade();

        if (list.size()>0){

            FirstBlock block = new FirstBlock();
            String index = redisService.get("blockIndex");
            if (StringUtils.isEmpty(index) && index == null){
                //直接从数据库查询
                if (!isHave){
                    //生成创世区块
                    mongoTradeService.tally(firstBlockforMongodb(),list);
                }else{
                    block = mongoTradeService.getNewest();
                    mongoTradeService.hyperledger(block,list);
                }

            }else {
                //查询区块信息
                block = mongoTradeService.getBlockByIndex(Integer.valueOf(index));
                if (block != null){
                    mongoTradeService.hyperledger(block,list);
                }else {
                    System.out.println("区块出现异常");
                }
            }

            //同步更新到其他三个节点
            SecondBlock secondBlock = secondService.getNewest();
            if (secondBlock == null){
                List<FirstBlock> firstBlocks = mongoTradeService.getCurrentBlocks(0);
                for (FirstBlock firstBlock : firstBlocks){
                    secondService.addBlock(ConvertUtil.convertSecond(firstBlock));
                    thirdService.addBlock(ConvertUtil.convertThird(firstBlock));
                    fourthService.addBlock(ConvertUtil.convertFourth(firstBlock));
                }
            }else {
                int secondNum           = secondBlock.getPointDeals().size();
                int secondIndex         = secondBlock.getIndex();
                if (BlockConstant.blockMax == secondNum){
                    //从下一区块开始同步
                    List<FirstBlock> firstBlocks = mongoTradeService.getCurrentBlocks(secondIndex+1);
                    for (FirstBlock firstBlock : firstBlocks){
                        secondService.addBlock(ConvertUtil.convertSecond(firstBlock));
                        thirdService.addBlock(ConvertUtil.convertThird(firstBlock));
                        fourthService.addBlock(ConvertUtil.convertFourth(firstBlock));
                    }
                }else {
                    //否则从当前更新区块
                    List<FirstBlock> firstBlocks = mongoTradeService.getCurrentBlocks(secondIndex);
                    for (FirstBlock firstBlock : firstBlocks){
                        secondService.addBlock(ConvertUtil.convertSecond(firstBlock));
                        thirdService.addBlock(ConvertUtil.convertThird(firstBlock));
                        fourthService.addBlock(ConvertUtil.convertFourth(firstBlock));
                    }
                }
            }
        }

    }



    public static Block firstBlockforMysql(){

        Block block = new Block();

        String prev          = "0000000000000000000000000000000000000000000000000000000000000000";
        int index            = 1;
        int nonce            = 1;
        long time            = System.currentTimeMillis();
        String hash          = EncryptUtil.Encrypt(prev+index+nonce+time);
        List<PointDeal> list = new ArrayList<>();

        block.setPreviousHash(prev);
        block.setIndex(index);
        block.setNonce(nonce);
        block.setHash(hash);
        block.setTimestamp(time);
        block.setPointDeals(list);
        block.setPointDeals(null);

        return block;
    }

    public static FirstBlock firstBlockforMongodb(){

        FirstBlock block = new FirstBlock();

        String prev = "0000000000000000000000000000000000000000000000000000000000000000";
        int index   = 1;
        int nonce   = 1;
        long time   = System.currentTimeMillis();
        String hash = EncryptUtil.Encrypt(prev+index+nonce+time);
        List<PointDeal> list = new ArrayList<>();


        block.setPreviousHash(prev);
        block.setIndex(index);
        block.setNonce(nonce);
        block.setHash(hash);
        block.setTimestamp(time);
        block.setPointDeals(null);
        block.setPointDeals(list);

        return block;
    }

    public boolean prove(int node){

        boolean isProve = false;


        switch (node){
            case 1:
                isProve = mongoTradeService.prove();
                break;
            case 2:
                isProve = secondService.prove();
                break;
            case 3:
                isProve = thirdService.prove();
                break;
            case 4:
                isProve = fourthService.prove();
                break;
            default:
                return false;

        }

        return isProve;
    }
}
